home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / unix.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  30KB  |  1,488 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * unix.c -- BSD and SYSV code
  11.  *
  12.  * A lot of this file was written by Juergen Weigert.
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "param.h"
  18. #include "proto.h"
  19.  
  20. #include <fcntl.h>
  21. #if !defined(pyr) && !defined(NOT_BOTH_TIME)
  22. # include <time.h>            /* on some systems time.h should not be
  23.                                included together with sys/time.h */
  24. #endif
  25. #include <sys/ioctl.h>
  26. #ifndef M_XENIX
  27. # include <sys/types.h>
  28. #endif
  29. #include <signal.h>
  30.  
  31. #ifndef USE_SYSTEM        /* use fork/exec to start the shell */
  32. # include <sys/wait.h>
  33. # if !defined(SCO) && !defined(SOLARIS) && !defined(hpux) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(_SEQUENT_) && !defined(UNISYS)    /* SCO returns pid_t */
  34. extern int fork();
  35. # endif
  36. # if !defined(linux) && !defined(SOLARIS) && !defined(USL) && !defined(sun) && !(defined(hpux) && defined(__STDC__)) && !defined(__NetBSD__) && !defined(__FreeBSD__) && !defined(USL) && !defined(UNISYS)
  37. extern int execvp __ARGS((const char *, const char **));
  38. # endif
  39. #endif
  40.  
  41. #if defined(SYSV_UNIX) || defined(USL)
  42. # if defined(__sgi) || defined(UTS2) || defined(UTS4) || defined(MIPS) || defined (MIPSEB) || defined(__osf__)
  43. #  include <sys/time.h>
  44. # endif
  45. # if defined(M_XENIX) || defined(SCO)
  46. #  include <stropts.h>
  47. # endif
  48. # if defined(M_XENIX) || defined(SCO) || defined(UNICOS)
  49. #  include <sys/select.h>
  50. #  define bzero(a, b)    memset((a), 0, (b))
  51. # endif
  52. # if !defined(M_XENIX) && !defined(UNICOS)
  53. #  include <poll.h>
  54. # endif
  55. # if defined(SCO) || defined(ISC)
  56. #  include <sys/stream.h>
  57. #  include <sys/ptem.h>
  58. # endif
  59. # if defined(M_UNIX) && !defined(SCO)
  60. #  include <sys/time.h>
  61. # endif       /* M_UNIX */
  62. # ifdef ISC
  63. #  include <termios.h>
  64. # endif
  65. # include <termio.h>
  66. #else    /* SYSV_UNIX */
  67. # include <sys/time.h>
  68. # if defined(hpux) || defined(linux)
  69. #  include <termio.h>
  70. #  if defined(hpux) && !defined(SIGWINCH)    /* hpux 9.01 has it */
  71. #   define SIGWINCH SIGWINDOW
  72. #  endif
  73. # else
  74. #  include <sgtty.h>
  75. # endif    /* hpux */
  76. #endif    /* !SYSV_UNIX */
  77.  
  78. #if (defined(pyr) || defined(NO_FD_ZERO)) && defined(SYSV_UNIX) && defined(FD_ZERO)
  79. # undef FD_ZERO
  80. #endif
  81.  
  82. #if defined(ESIX) || defined(M_UNIX) && !defined(SCO)
  83. # ifdef SIGWINCH
  84. #  undef SIGWINCH
  85. # endif
  86. # ifdef TIOCGWINSZ
  87. #  undef TIOCGWINSZ
  88. # endif
  89. #endif
  90.  
  91. #ifdef USE_X11
  92.  
  93. # include <X11/Xlib.h>
  94. # include <X11/Xutil.h>
  95.  
  96. Window        x11_window = 0;
  97. Display        *x11_display = NULL;
  98.  
  99. static int    get_x11_windis __ARGS((void));
  100. #ifdef BUGGY
  101. static void set_x11_title __ARGS((char_u *));
  102. static void set_x11_icon __ARGS((char_u *));
  103. #endif
  104. #endif
  105.  
  106. static void get_x11_title __ARGS((void));
  107. static void get_x11_icon __ARGS((void));
  108.  
  109. static int    Read __ARGS((char_u *, long));
  110. static int    WaitForChar __ARGS((int));
  111. static int    RealWaitForChar __ARGS((int));
  112. static void fill_inbuf __ARGS((void));
  113. #ifdef USL
  114. static void sig_winch __ARGS((int));
  115. #else
  116. # if defined(SIGWINCH) && !defined(linux) && !defined(__alpha) && !defined(mips) && !defined(_SEQUENT_) && !defined(SCO) && !defined(SOLARIS) && !defined(ISC)
  117. static void sig_winch __ARGS((int, int, struct sigcontext *));
  118. # endif
  119. #endif
  120.  
  121. static int do_resize = FALSE;
  122. static char_u *oldtitle = NULL;
  123. static char_u *oldicon = NULL;
  124. static char_u *extra_shell_arg = NULL;
  125. static int show_shell_mess = TRUE;
  126.  
  127. /*
  128.  * At this point TRUE and FALSE are defined as 1L and 0L, but we want 1 and 0.
  129.  */
  130. #undef TRUE
  131. #define TRUE 1
  132. #undef FALSE
  133. #define FALSE 0
  134.  
  135.     void
  136. mch_write(s, len)
  137.     char_u    *s;
  138.     int        len;
  139. {
  140.     write(1, (char *)s, len);
  141. }
  142.  
  143. /*
  144.  * GetChars(): low level input funcion.
  145.  * Get a characters from the keyboard.
  146.  * If wtime == 0 do not wait for characters.
  147.  * If wtime == n wait a short time for characters.
  148.  * If wtime == -1 wait forever for characters.
  149.  */
  150.     int
  151. GetChars(buf, maxlen, wtime)
  152.     char_u    *buf;
  153.     int        maxlen;
  154.     int        wtime;            /* don't use "time", MIPS cannot handle it */
  155. {
  156.     int        len;
  157.  
  158.     if (wtime >= 0)
  159.     {
  160.         while (WaitForChar(wtime) == 0)        /* no character available */
  161.         {
  162.             if (!do_resize)            /* return if not interrupted by resize */
  163.                 return 0;
  164.             set_winsize(0, 0, FALSE);
  165.             do_resize = FALSE;
  166.         }
  167.     }
  168.     else        /* wtime == -1 */
  169.     {
  170.     /*
  171.      * If there is no character available within 'updatetime' seconds
  172.      * flush all the swap files to disk
  173.      * Also done when interrupted by SIGWINCH.
  174.      */
  175.         if (WaitForChar((int)p_ut) == 0)
  176.             updatescript(0);
  177.     }
  178.  
  179.     for (;;)    /* repeat until we got a character */
  180.     {
  181.         if (do_resize)        /* window changed size */
  182.         {
  183.             set_winsize(0, 0, FALSE);
  184.             do_resize = FALSE;
  185.         }
  186.         /* 
  187.          * we want to be interrupted by the winch signal
  188.          */
  189.         WaitForChar(-1);
  190.         if (do_resize)        /* interrupted by SIGWINCHsignal */
  191.             continue;
  192.         len = Read(buf, (long)maxlen);
  193.         if (len > 0)
  194.             return len;
  195.     }
  196. }
  197.  
  198. /*
  199.  * return non-zero if a character is available
  200.  */
  201.     int
  202. mch_char_avail()
  203. {
  204.     return WaitForChar(0);
  205. }
  206.  
  207.     long
  208. mch_avail_mem(special)
  209.     int special;
  210. {
  211.     return 0x7fffffff;        /* virual memory eh */
  212. }
  213.  
  214. #ifndef FD_ZERO
  215.     void
  216. vim_delay()
  217. {
  218.     poll(0, 0, 500);
  219. }
  220. #else
  221. # if (defined(__STDC__) && !defined(hpux)) || defined(ultrix)
  222. extern int select __ARGS((int, fd_set *, fd_set *, fd_set *, struct timeval *));
  223. # endif
  224.  
  225.     void
  226. vim_delay()
  227. {
  228.     struct timeval tv;
  229.  
  230.     tv.tv_sec = 25 / 50;
  231.     tv.tv_usec = (25 % 50) * (1000000/50);
  232.     select(0, 0, 0, 0, &tv);
  233. }
  234. #endif
  235.  
  236.     static void
  237. #if defined(__alpha) || (defined(mips) && !defined(USL))
  238. sig_winch()
  239. #else
  240. # if defined(_SEQUENT_) || defined(SCO) || defined(ISC)
  241. sig_winch(sig, code)
  242.     int        sig;
  243.     int        code;
  244. # else
  245. #  if defined(USL)
  246. sig_winch(sig)
  247.     int        sig;
  248. #  else
  249. sig_winch(sig, code, scp)
  250.     int        sig;
  251.     int        code;
  252.     struct sigcontext *scp;
  253. #  endif
  254. # endif
  255. #endif
  256. {
  257. #if defined(SIGWINCH)
  258.         /* this is not required on all systems, but it doesn't hurt anybody */
  259.     signal(SIGWINCH, (void (*)())sig_winch);
  260. #endif
  261.     do_resize = TRUE;
  262. }
  263.  
  264. /*
  265.  * If the machine has job control, use it to suspend the program,
  266.  * otherwise fake it by starting a new shell.
  267.  */
  268.     void
  269. mch_suspend()
  270. {
  271. #ifdef SIGTSTP
  272.     settmode(0);
  273.     kill(0, SIGTSTP);        /* send ourselves a STOP signal */
  274.     settmode(1);
  275. #else
  276.     OUTSTR("new shell started\n");
  277.     (void)call_shell(NULL, 0, TRUE);
  278. #endif
  279. }
  280.  
  281.     void
  282. mch_windinit()
  283. {
  284.     Columns = 80;
  285.     Rows = 24;
  286.  
  287.     flushbuf();
  288.  
  289.     (void)mch_get_winsize();
  290. #if defined(SIGWINCH)
  291.     signal(SIGWINCH, (void (*)())sig_winch);
  292. #endif
  293. }
  294.  
  295. /*
  296.  * Check_win checks whether we have an interactive window.
  297.  * If not, a new window is opened with the newcli command.
  298.  * If we would open a window ourselves, the :sh and :! commands would not
  299.  * work properly (Why? probably because we are then running in a background CLI).
  300.  * This also is the best way to assure proper working in a next Workbench release.
  301.  *
  302.  * For the -e option (quickfix mode) we open our own window and disable :sh.
  303.  * Otherwise we would never know when editing is finished.
  304.  */
  305. #define BUF2SIZE 320        /* lenght of buffer for argument with complete path */
  306.  
  307.     void
  308. check_win(argc, argv)
  309.     int        argc;
  310.     char    **argv;
  311. {
  312.     if (!isatty(0) || !isatty(1))
  313.     {
  314.         fprintf(stderr, "VIM: no controlling terminal\n");
  315.         exit(2);
  316.     }
  317. }
  318.  
  319. /*
  320.  * fname_case(): Set the case of the filename, if it already exists.
  321.  *                 This will cause the filename to remain exactly the same.
  322.  */
  323.     void
  324. fname_case(name)
  325.     char_u *name;
  326. {
  327. }
  328.  
  329. #ifdef USE_X11
  330. /*
  331.  * try to get x11 window and display
  332.  *
  333.  * return FAIL for failure, OK otherwise
  334.  */
  335.     static int
  336. get_x11_windis()
  337. {
  338.     char        *winid;
  339.  
  340.     /*
  341.      * If WINDOWID not set, should try another method to find out
  342.      * what the current window number is. The only code I know for
  343.      * this is very complicated.
  344.      * We assume that zero is invalid for WINDOWID.
  345.      */
  346.     if (x11_window == 0 && (winid = getenv("WINDOWID")) != NULL) 
  347.         x11_window = (Window)atol(winid);
  348.     if (x11_window != 0 && x11_display == NULL)
  349.         x11_display = XOpenDisplay(NULL);
  350.     if (x11_window == 0 || x11_display == NULL)
  351.         return FAIL;
  352.     return OK;
  353. }
  354.  
  355. /*
  356.  * Determine original x11 Window Title
  357.  */
  358.     static void
  359. get_x11_title()
  360. {
  361.     XTextProperty    text_prop;
  362.  
  363.     if (get_x11_windis() == OK)
  364.     {
  365.             /* Get window name if any */
  366.         if (XGetWMName(x11_display, x11_window, &text_prop))
  367.         {
  368.             if (text_prop.value != NULL)
  369.                 oldtitle = strsave((char_u *)text_prop.value);
  370.             XFree((void *)text_prop.value);
  371.         }
  372.     }
  373.     if (oldtitle == NULL)        /* could not get old title */
  374.         oldtitle = (char_u *)"Thanks for flying Vim";
  375. }
  376.  
  377. /*
  378.  * Determine original x11 Window icon
  379.  */
  380.  
  381.     static void
  382. get_x11_icon()
  383. {
  384.     XTextProperty text_prop;
  385.  
  386.     if (get_x11_windis() == OK)
  387.     {
  388.             /* Get icon name if any */
  389.         if (XGetWMIconName(x11_display, x11_window, &text_prop))
  390.         {
  391.             if (text_prop.value != NULL)
  392.                 oldicon = strsave((char_u *)text_prop.value);
  393.             XFree((void *)text_prop.value);
  394.         }
  395.     }
  396.  
  397.         /* could not get old icon, use terminal name */
  398.     if (oldicon == NULL)
  399.     {
  400.         if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
  401.             oldicon = term_strings.t_name + 8;
  402.         else
  403.             oldicon = term_strings.t_name;
  404.     }
  405. }
  406.  
  407. #if BUGGY
  408.  
  409. This is not included, because it probably does not work at all.
  410. On my FreeBSD/Xfree86 in a shelltool I get all kinds of error messages and
  411. Vim is stopped in an uncontrolled way.
  412.  
  413. /*
  414.  * Set x11 Window Title
  415.  *
  416.  * get_x11_windis() must be called before this and have returned OK
  417.  */
  418.     static void
  419. set_x11_title(title)
  420.     char_u        *title;
  421. {
  422.     XTextProperty text_prop;
  423.  
  424.         /* Get icon name if any */
  425.     text_prop.value = title;
  426.     text_prop.nitems = STRLEN(title);
  427.     XSetWMName(x11_display, x11_window, &text_prop);
  428.     if (XGetWMName(x11_display, x11_window, &text_prop))     /* required? */
  429.         XFree((void *)text_prop.value);
  430. }
  431.  
  432. /*
  433.  * Set x11 Window icon
  434.  *
  435.  * get_x11_windis() must be called before this and have returned OK
  436.  */
  437.     static void
  438. set_x11_icon(icon)
  439.     char_u        *icon;
  440. {
  441.     XTextProperty text_prop;
  442.  
  443.         /* Get icon name if any */
  444.     text_prop.value = icon;
  445.     text_prop.nitems = STRLEN(icon);
  446.     XSetWMIconName(x11_display, x11_window, &text_prop);
  447.     if (XGetWMIconName(x11_display, x11_window, &text_prop)) /* required? */
  448.         XFree((void *)text_prop.value);
  449. }
  450. #endif
  451.  
  452. #else    /* USE_X11 */
  453.  
  454.     static void
  455. get_x11_title()
  456. {
  457.     oldtitle = (char_u *)"Thanks for flying Vim";
  458. }
  459.  
  460.     static void
  461. get_x11_icon()
  462. {
  463.     if (STRNCMP(term_strings.t_name, "builtin_", 8) == 0)
  464.         oldicon = term_strings.t_name + 8;
  465.     else
  466.         oldicon = term_strings.t_name;
  467. }
  468.  
  469. #endif    /* USE_X11 */
  470.  
  471.  
  472. /*
  473.  * set the window title and icon
  474.  * Currently only works for x11.
  475.  */
  476.     void
  477. mch_settitle(title, icon)
  478.     char_u *title;
  479.     char_u *icon;
  480. {
  481.     int            type = 0;
  482.  
  483.     if (term_strings.t_name == NULL)        /* no terminal name (yet) */
  484.         return;
  485.  
  486. /*
  487.  * if the window ID and the display is known, we may use X11 calls
  488.  */
  489. #ifdef USE_X11
  490.     if (get_x11_windis() == OK)
  491.         type = 1;
  492. #endif
  493.  
  494.     /*
  495.      * note: if terminal is xterm, title is set with escape sequence rather
  496.      *          than x11 calls, because the x11 calls don't always work
  497.      */
  498.     if (    STRCMP(term_strings.t_name, "xterm") == 0 ||
  499.             STRCMP(term_strings.t_name, "builtin_xterm") == 0)
  500.         type = 2;
  501.  
  502.         /*
  503.          * Note: getting the old window title for iris-ansi will only
  504.          * currently work if you set WINDOWID by hand, it is not
  505.          * done automatically like an xterm.
  506.          */
  507.     if (STRCMP(term_strings.t_name, "iris-ansi") == 0 ||
  508.              STRCMP(term_strings.t_name, "iris-ansi-net") == 0)
  509.         type = 3;
  510.  
  511.     if (type)
  512.     {
  513.         if (title != NULL)
  514.         {
  515.             if (oldtitle == NULL)                /* first call, save title */
  516.                 get_x11_title();
  517.  
  518.             switch(type)
  519.             {
  520. #ifdef USE_X11
  521. #ifdef BUGGY
  522.             case 1:    set_x11_title(title);                /* x11 */
  523.                     break;
  524. #endif
  525. #endif
  526.             case 2: outstrn((char_u *)"\033]2;");        /* xterm */
  527.                     outstrn(title);
  528.                     outchar(Ctrl('G'));
  529.                     flushbuf();
  530.                     break;
  531.  
  532.             case 3: outstrn((char_u *)"\033P1.y");        /* iris-ansi */
  533.                     outstrn(title);
  534.                     outstrn((char_u *)"\234");
  535.                     flushbuf();
  536.                     break;
  537.             }
  538.         }
  539.  
  540.         if (icon != NULL)
  541.         {
  542.             if (oldicon == NULL)                /* first call, save icon */
  543.                 get_x11_icon();
  544.  
  545.             switch(type)
  546.             {
  547. #ifdef USE_X11
  548. #ifdef BUGGY
  549.             case 1:    set_x11_icon(icon);                    /* x11 */
  550.                     break;
  551. #endif
  552. #endif
  553.             case 2: outstrn((char_u *)"\033]1;");        /* xterm */
  554.                     outstrn(icon);
  555.                     outchar(Ctrl('G'));
  556.                     flushbuf();
  557.                     break;
  558.  
  559.             case 3: outstrn((char_u *)"\033P3.y");        /* iris-ansi */
  560.                     outstrn(icon);
  561.                     outstrn((char_u *)"\234");
  562.                     flushbuf();
  563.                     break;
  564.             }
  565.         }
  566.     }
  567. }
  568.  
  569. /*
  570.  * Restore the window/icon title.
  571.  * which is one of:
  572.  *    1  Just restore title
  573.  *  2  Just restore icon
  574.  *    3  Restore title and icon
  575.  */
  576.     void
  577. mch_restore_title(which)
  578.     int which;
  579. {
  580.     mch_settitle((which & 1) ? oldtitle : NULL, (which & 2) ? oldicon : NULL);
  581. }
  582.  
  583. /*
  584.  * Get name of current directory into buffer 'buf' of length 'len' bytes.
  585.  * Return OK for success, FAIL for failure.
  586.  */
  587.     int 
  588. vim_dirname(buf, len)
  589.     char_u *buf;
  590.     int len;
  591. {
  592. #if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  593.     extern int        errno;
  594.     extern char        *sys_errlist[];
  595.  
  596.     if (getcwd((char *)buf, len) == NULL)
  597.     {
  598.         STRCPY(buf, sys_errlist[errno]);
  599.         return FAIL;
  600.     }
  601.     return OK;
  602. #else
  603.     return (getwd((char *)buf) != NULL ? OK : FAIL);
  604. #endif
  605. }
  606.  
  607. /*
  608.  * get absolute filename into buffer 'buf' of length 'len' bytes
  609.  *
  610.  * return FAIL for failure, OK for success
  611.  */
  612.     int 
  613. FullName(fname, buf, len)
  614.     char_u *fname, *buf;
  615.     int len;
  616. {
  617.     int        l;
  618.     char_u    olddir[MAXPATHL];
  619.     char_u    *p;
  620.     int        c;
  621.     int        retval = OK;
  622.  
  623.     if (fname == NULL)    /* always fail */
  624.     {
  625.         *buf = NUL;
  626.         return FAIL;
  627.     }
  628.  
  629.     *buf = 0;
  630.     if (!isFullName(fname))            /* if not an absolute path */
  631.     {
  632.         /*
  633.          * If the file name has a path, change to that directory for a moment,
  634.          * and then do the getwd() (and get back to where we were).
  635.          * This will get the correct path name with "../" things.
  636.          */
  637.         if ((p = STRRCHR(fname, '/')) != NULL)
  638.         {
  639. #if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  640.             if (getcwd((char *)olddir, MAXPATHL) == NULL)
  641. #else
  642.             if (getwd((char *)olddir) == NULL)
  643. #endif
  644.             {
  645.                 p = NULL;        /* can't get current dir: don't chdir */
  646.                 retval = FAIL;
  647.             }
  648.             else
  649.             {
  650.                 c = *p;
  651.                 *p = NUL;
  652.                 if (chdir((char *)fname))
  653.                     retval = FAIL;
  654.                 else
  655.                     fname = p + 1;
  656.                 *p = c;
  657.             }
  658.         }
  659. #if defined(SYSV_UNIX) || defined(USL) || defined(hpux) || defined(linux)
  660.         if (getcwd((char *)buf, len) == NULL)
  661. #else
  662.         if (getwd((char *)buf) == NULL)
  663. #endif
  664.         {
  665.             retval = FAIL;
  666.             *buf = NUL;
  667.         }
  668.         l = STRLEN(buf);
  669.         if (l && buf[l - 1] != '/')
  670.             STRCAT(buf, "/");
  671.         if (p)
  672.             chdir((char *)olddir);
  673.     }
  674.     STRCAT(buf, fname);
  675.     return retval;
  676. }
  677.  
  678. /*
  679.  * return TRUE is fname is an absolute path name
  680.  */
  681.     int
  682. isFullName(fname)
  683.     char_u        *fname;
  684. {
  685.     return (*fname == '/');
  686. }
  687.  
  688. /*
  689.  * get file permissions for 'name'
  690.  */
  691.     long 
  692. getperm(name)
  693.     char_u *name;
  694. {
  695.     struct stat statb;
  696.  
  697.     if (stat((char *)name, &statb))
  698.         return -1;
  699.     return statb.st_mode;
  700. }
  701.  
  702. /*
  703.  * set file permission for 'name' to 'perm'
  704.  *
  705.  * return FAIL for failure, OK otherwise
  706.  */
  707.     int
  708. setperm(name, perm)
  709.     char_u *name;
  710.     int perm;
  711. {
  712. #ifdef SCO
  713.     return (chmod((char *)name, (mode_t)perm) == 0 ? OK : FAIL);
  714. #else
  715.     return (chmod((char *)name, perm) == 0 ? OK : FAIL);
  716. #endif
  717. }
  718.  
  719. /*
  720.  * return TRUE if "name" is a directory
  721.  * return FALSE if "name" is not a directory
  722.  * return -1 for error
  723.  */
  724.     int 
  725. isdir(name)
  726.     char_u *name;
  727. {
  728.     struct stat statb;
  729.  
  730.     if (stat((char *)name, &statb))
  731.         return -1;
  732. #ifdef _POSIX_SOURCE
  733.     return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
  734. #else
  735.     return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
  736. #endif
  737. }
  738.  
  739.     void
  740. mch_windexit(r)
  741.     int r;
  742. {
  743.     settmode(0);
  744.     exiting = TRUE;
  745.     mch_settitle(oldtitle, oldicon);    /* restore xterm title */
  746.     stoptermcap();
  747.     flushbuf();
  748.     ml_close_all();                 /* remove all memfiles */
  749.     exit(r);
  750. }
  751.  
  752.     void
  753. mch_settmode(raw)
  754.     int                raw;
  755. {
  756. #if defined(ECHOE) && defined(ICANON) && !defined(__NeXT__)
  757.     /* for "new" tty systems */
  758. # ifdef CONVEX
  759.     static struct termios told;
  760.            struct termios tnew;
  761. # else
  762.     static struct termio told;
  763.            struct termio tnew;
  764. # endif
  765. #ifdef TIOCLGET
  766.     static unsigned long tty_local;
  767. #endif
  768.  
  769.     if (raw)
  770.     {
  771. #ifdef TIOCLGET
  772.         ioctl(0, TIOCLGET, &tty_local);
  773. #endif
  774.         ioctl(0, TCGETA, &told);
  775.         tnew = told;
  776.         /*
  777.          * ICRNL enables typing ^V^M
  778.          */
  779.         tnew.c_iflag &= ~ICRNL;
  780.         tnew.c_lflag &= ~(ICANON | ECHO | ISIG | ECHOE
  781. #ifdef IEXTEN
  782.                     | IEXTEN        /* IEXTEN enables typing ^V on SOLARIS */
  783. #endif
  784.                         );
  785.         tnew.c_cc[VMIN] = 1;            /* return after 1 char */
  786.         tnew.c_cc[VTIME] = 0;            /* don't wait */
  787.         ioctl(0, TCSETA, &tnew);
  788.     }
  789.     else
  790.     {
  791.         ioctl(0, TCSETA, &told);
  792. #ifdef TIOCLGET
  793.         ioctl(0, TIOCLSET, &tty_local);
  794. #endif
  795.     }
  796. #else
  797. # ifndef TIOCSETN
  798. #  define TIOCSETN TIOCSETP        /* for hpux 9.0 */
  799. # endif
  800.     /* for "old" tty systems */
  801.     static struct sgttyb ttybold;
  802.            struct sgttyb ttybnew;
  803.  
  804.     if (raw)
  805.     {
  806.         ioctl(0, TIOCGETP, &ttybold);
  807.         ttybnew = ttybold;
  808.         ttybnew.sg_flags &= ~(CRMOD | ECHO);
  809.         ttybnew.sg_flags |= RAW;
  810.         ioctl(0, TIOCSETN, &ttybnew);
  811.     }
  812.     else
  813.         ioctl(0, TIOCSETN, &ttybold);
  814. #endif
  815. }
  816.  
  817. /*
  818.  * set screen mode, always fails.
  819.  */
  820.     int
  821. mch_screenmode(arg)
  822.     char_u     *arg;
  823. {
  824.     EMSG("Screen mode setting not supported");
  825.     return FAIL;
  826. }
  827.  
  828. /*
  829.  * Try to get the current window size:
  830.  * 1. with an ioctl(), most accurate method
  831.  * 2. from the environment variables LINES and COLUMNS
  832.  * 3. from the termcap
  833.  * 4. keep using the old values
  834.  */
  835.     int
  836. mch_get_winsize()
  837. {
  838.     int            old_Rows = Rows;
  839.     int            old_Columns = Columns;
  840.     char_u        *p;
  841.  
  842.     Columns = 0;
  843.     Rows = 0;
  844.  
  845. /*
  846.  * 1. try using an ioctl. It is the most accurate method.
  847.  */
  848. # ifdef TIOCGSIZE
  849.     {
  850.         struct ttysize    ts;
  851.  
  852.         if (ioctl(0, TIOCGSIZE, &ts) == 0)
  853.         {
  854.             Columns = ts.ts_cols;
  855.             Rows = ts.ts_lines;
  856.         }
  857.     }
  858. # else /* TIOCGSIZE */
  859. #  ifdef TIOCGWINSZ
  860.     {
  861.         struct winsize    ws;
  862.  
  863.         if (ioctl(0, TIOCGWINSZ, &ws) == 0)
  864.         {
  865.             Columns = ws.ws_col;
  866.             Rows = ws.ws_row;
  867.         }
  868.     }
  869. #  endif /* TIOCGWINSZ */
  870. # endif /* TIOCGSIZE */
  871.  
  872. /*
  873.  * 2. get size from environment
  874.  */
  875.     if (Columns == 0 || Rows == 0)
  876.     {
  877.         if ((p = (char_u *)getenv("LINES")))
  878.             Rows = atoi((char *)p);
  879.         if ((p = (char_u *)getenv("COLUMNS")))
  880.             Columns = atoi((char *)p);
  881.     }
  882.  
  883. #ifdef TERMCAP
  884. /*
  885.  * 3. try reading the termcap
  886.  */
  887.     if (Columns == 0 || Rows == 0)
  888.     {
  889.         extern void getlinecol();
  890.  
  891.         getlinecol();    /* get "co" and "li" entries from termcap */
  892.     }
  893. #endif
  894.  
  895. /*
  896.  * 4. If everything fails, use the old values
  897.  */
  898.     if (Columns <= 0 || Rows <= 0)
  899.     {
  900.         Columns = old_Columns;
  901.         Rows = old_Rows;
  902.         return FAIL;
  903.     }
  904.  
  905.     check_winsize();
  906.  
  907. /* if size changed: screenalloc will allocate new screen buffers */
  908.     return OK;
  909. }
  910.  
  911.     void
  912. mch_set_winsize()
  913. {
  914.     /* should try to set the window size to Rows and Columns */
  915. }
  916.  
  917.     int 
  918. call_shell(cmd, dummy, cooked)
  919.     char_u    *cmd;
  920.     int        dummy;
  921.     int        cooked;
  922. {
  923. #ifdef USE_SYSTEM        /* use system() to start the shell: simple but slow */
  924.  
  925.     int        x;
  926.     char_u    newcmd[1024];
  927.  
  928.     flushbuf();
  929.  
  930.     if (cooked)
  931.         settmode(0);                 /* set to cooked mode */
  932.  
  933.     if (cmd == NULL)
  934.         x = system(p_sh);
  935.     else
  936.     {
  937.         sprintf(newcmd, "%s %s -c \"%s\"", p_sh,
  938.                         extra_shell_arg == NULL ? "" : extra_shell_arg, cmd);
  939.         x = system(newcmd);
  940.     }
  941.     if (x == 127)
  942.     {
  943.         outstrn((char_u *)"\nCannot execute shell sh\n");
  944.     }
  945. #ifdef WEBB_COMPLETE
  946.     else if (x && !expand_interactively)
  947. #else
  948.     else if (x)
  949. #endif
  950.     {
  951.         outchar('\n');
  952.         outnum((long)x);
  953.         outstrn((char_u *)" returned\n");
  954.     }
  955.  
  956.     if (cooked)
  957.         settmode(1);                         /* set to raw mode */
  958.     resettitle();
  959.     return (x ? FAIL : OK);
  960.  
  961. #else /* USE_SYSTEM */        /* first attempt at not using system() */
  962.  
  963.     char_u    newcmd[1024];
  964.     int        pid;
  965.     int        status = -1;
  966.     char    **argv = NULL;
  967.     int        argc;
  968.     int        i;
  969.     char_u    *p;
  970.     int        inquote;
  971.  
  972.     flushbuf();
  973.     signal(SIGINT, SIG_IGN);    /* we don't want to be killed here */
  974.     if (cooked)
  975.         settmode(0);            /* set to cooked mode */
  976.  
  977.     /*
  978.      * 1: find number of arguments
  979.      * 2: separate them and built argv[]
  980.      */
  981.     STRCPY(newcmd, p_sh);
  982.     for (i = 0; i < 2; ++i)    
  983.     {
  984.         p = newcmd;
  985.         inquote = FALSE;
  986.         argc = 0;
  987.         for (;;)
  988.         {
  989.             if (i == 1)
  990.                 argv[argc] = (char *)p;
  991.             ++argc;
  992.             while (*p && (inquote || (*p != ' ' && *p != TAB)))
  993.             {
  994.                 if (*p == '"')
  995.                     inquote = !inquote;
  996.                 ++p;
  997.             }
  998.             if (*p == NUL)
  999.                 break;
  1000.             if (i == 1)
  1001.                 *p++ = NUL;
  1002.             skipspace(&p);
  1003.         }
  1004.         if (i == 0)
  1005.         {
  1006.             argv = (char **)alloc((unsigned)((argc + 4) * sizeof(char *)));
  1007.             if (argv == NULL)        /* out of memory */
  1008.                 goto error;
  1009.         }
  1010.     }
  1011.     if (cmd != NULL)
  1012.     {
  1013.         if (extra_shell_arg != NULL)
  1014.             argv[argc++] = (char *)extra_shell_arg;
  1015.         argv[argc++] = "-c";
  1016.         argv[argc++] = (char *)cmd;
  1017.     }
  1018.     argv[argc] = NULL;
  1019.  
  1020.     if ((pid = fork()) == -1)        /* maybe we should use vfork() */
  1021.     {
  1022.         outstrn((char_u *)"\nCannot fork\n");
  1023.     }
  1024.     else if (pid == 0)        /* child */
  1025.     {
  1026.         signal(SIGINT, SIG_DFL);
  1027.         if (!show_shell_mess)
  1028.         {
  1029.             fclose(stdout);
  1030.             fclose(stderr);
  1031.         }
  1032.         execvp(argv[0], (char **)argv);
  1033.         exit(127);            /* exec failed, return failure code */
  1034.     }
  1035.     else                    /* parent */
  1036.     {
  1037.         wait(&status);
  1038.         status = (status >> 8) & 255;
  1039.         if (status)
  1040.         {
  1041. #ifdef WEBB_COMPLETE
  1042.             if (status == 127)
  1043.             {
  1044.                 outstrn((char_u *)"\nCannot execute shell ");
  1045.                 outstrn(p_sh);
  1046.                 outchar('\n');
  1047.             }
  1048.             else if (!expand_interactively)
  1049.             {
  1050.                 outchar('\n');
  1051.                 outnum((long)status);
  1052.                 outstrn((char_u *)" returned\n");
  1053.             }
  1054. #else
  1055.             outchar('\n');
  1056.             if (status == 127)
  1057.             {
  1058.                 outstrn((char_u *)"Cannot execute shell ");
  1059.                 outstrn(p_sh);
  1060.             }
  1061.             else
  1062.             {
  1063.                 outnum((long)status);
  1064.                 outstrn((char_u *)" returned");
  1065.             }
  1066.             outchar('\n');
  1067. #endif /* WEBB_COMPLETE */
  1068.         }
  1069.     }
  1070.     free(argv);
  1071.  
  1072. error:
  1073.     if (cooked)
  1074.         settmode(1);                         /* set to raw mode */
  1075.     resettitle();
  1076.     signal(SIGINT, SIG_DFL);
  1077.     return (status ? FAIL : OK);
  1078.  
  1079. #endif /* USE_SYSTEM */
  1080. }
  1081.  
  1082. /*
  1083.  * The input characters are buffered to be able to check for a CTRL-C.
  1084.  * This should be done with signals, but I don't know how to do that in
  1085.  * a portable way for a tty in RAW mode.
  1086.  */
  1087.  
  1088. #define INBUFLEN 250
  1089. static char_u        inbuf[INBUFLEN];    /* internal typeahead buffer */
  1090. static int        inbufcount = 0;        /* number of chars in inbuf[] */
  1091.  
  1092.     static int
  1093. Read(buf, maxlen)
  1094.     char_u    *buf;
  1095.     long    maxlen;
  1096. {
  1097.     if (inbufcount == 0)        /* if the buffer is empty, fill it */
  1098.         fill_inbuf();
  1099.     if (maxlen > inbufcount)
  1100.         maxlen = inbufcount;
  1101.     memmove((char *)buf, (char *)inbuf, maxlen);
  1102.     inbufcount -= maxlen;
  1103.     if (inbufcount)
  1104.         memmove((char *)inbuf, (char *)inbuf + maxlen, inbufcount);
  1105.     return (int)maxlen;
  1106. }
  1107.  
  1108.     void
  1109. breakcheck()
  1110. {
  1111. /*
  1112.  * check for CTRL-C typed by reading all available characters
  1113.  */
  1114.     if (RealWaitForChar(0))        /* if characters available */
  1115.         fill_inbuf();
  1116. }
  1117.  
  1118.     static void
  1119. fill_inbuf()
  1120. {
  1121.     int        len;
  1122.  
  1123.     if (inbufcount >= INBUFLEN)        /* buffer full */
  1124.         return;
  1125.     len = read(0, inbuf + inbufcount, (long)(INBUFLEN - inbufcount));
  1126.     if (len <= 0)    /* cannot read input??? */
  1127.     {
  1128.         fprintf(stderr, "Vim: Error reading input, exiting...\n");
  1129.         exit(1);
  1130.     }
  1131.     while (len-- > 0)
  1132.     {
  1133.         /*
  1134.          * if a CTRL-C was typed, remove it from the buffer and set got_int
  1135.          */
  1136.         if (inbuf[inbufcount] == 3)
  1137.         {
  1138.             /* remove everything typed before the CTRL-C */
  1139.             memmove((char *)inbuf, (char *)inbuf + inbufcount, len + 1);
  1140.             inbufcount = 0;
  1141.             got_int = TRUE;
  1142.         }
  1143.         ++inbufcount;
  1144.     }
  1145. }
  1146.  
  1147. /* 
  1148.  * Wait "ticks" until a character is available from the keyboard or from inbuf[]
  1149.  * ticks = -1 will block forever
  1150.  */
  1151.  
  1152.     static int
  1153. WaitForChar(ticks)
  1154.     int ticks;
  1155. {
  1156.     if (inbufcount)        /* something in inbuf[] */
  1157.         return 1;
  1158.     return RealWaitForChar(ticks);
  1159. }
  1160.  
  1161. /* 
  1162.  * Wait "ticks" until a character is available from the keyboard
  1163.  * ticks = -1 will block forever
  1164.  */
  1165.     static int
  1166. RealWaitForChar(ticks)
  1167.     int ticks;
  1168. {
  1169. #ifndef FD_ZERO
  1170.     struct pollfd fds;
  1171.  
  1172.     fds.fd = 0;
  1173.     fds.events = POLLIN;
  1174.     return (poll(&fds, 1, ticks));
  1175. #else
  1176.     struct timeval tv;
  1177.     fd_set fdset;
  1178.  
  1179.     if (ticks >= 0)
  1180.     {
  1181.            tv.tv_sec = ticks / 1000;
  1182.         tv.tv_usec = (ticks % 1000) * (1000000/1000);
  1183.     }
  1184.  
  1185.     FD_ZERO(&fdset);
  1186.     FD_SET(0, &fdset);
  1187.     return (select(1, &fdset, NULL, NULL, (ticks >= 0) ? &tv : NULL));
  1188. #endif
  1189. }
  1190.  
  1191. #if !defined(__alpha) && !defined(mips) && !defined(SCO) && !defined(remove) && !defined(CONVEX)
  1192.     int 
  1193. remove(buf)
  1194. # if defined(linux) || defined(__STDC__) || defined(__NeXT__) || defined(M_UNIX)
  1195.     const
  1196. # endif
  1197.             char *buf;
  1198. {
  1199.     return unlink(buf);
  1200. }
  1201. #endif
  1202.  
  1203. /*
  1204.  * ExpandWildCard() - this code does wild-card pattern matching using the shell
  1205.  *
  1206.  * Mool: return 0 for success, 1 for error (you may loose some memory) and
  1207.  *       put an error message in *file.
  1208.  *
  1209.  * num_pat is number of input patterns
  1210.  * pat is array of pointers to input patterns
  1211.  * num_file is pointer to number of matched file names
  1212.  * file is pointer to array of pointers to matched file names
  1213.  * On Unix we do not check for files only yet
  1214.  * list_notfound is ignored
  1215.  */
  1216.  
  1217. extern char *mktemp __ARGS((char *));
  1218. #ifndef SEEK_SET
  1219. # define SEEK_SET 0
  1220. #endif
  1221. #ifndef SEEK_END
  1222. # define SEEK_END 2
  1223. #endif
  1224.  
  1225.     int
  1226. ExpandWildCards(num_pat, pat, num_file, file, files_only, list_notfound)
  1227.     int             num_pat;
  1228.     char_u          **pat;
  1229.     int            *num_file;
  1230.     char_u         ***file;
  1231.     int                files_only;
  1232.     int                list_notfound;
  1233. {
  1234.     char_u    tmpname[TMPNAMELEN];
  1235.     char_u    *command;
  1236.     int        i;
  1237.     int        dir;
  1238.     size_t    len;
  1239.     FILE    *fd;
  1240.     char_u    *buffer;
  1241.     char_u    *p;
  1242.     int        use_glob = FALSE;
  1243.  
  1244.     *num_file = 0;        /* default: no files found */
  1245.     *file = (char_u **)"";
  1246.  
  1247.     /*
  1248.      * If there are no wildcards, just copy the names to allocated memory.
  1249.      * Saves a lot of time, because we don't have to start a new shell.
  1250.      */
  1251.     if (!have_wildcard(num_pat, pat))
  1252.     {
  1253.         *file = (char_u **)alloc(num_pat * sizeof(char_u *));
  1254.         if (*file == NULL)
  1255.         {
  1256.             *file = (char_u **)"";
  1257.             return FAIL;
  1258.         }
  1259.         for (i = 0; i < num_pat; i++)
  1260.             (*file)[i] = strsave(pat[i]);
  1261.         *num_file = num_pat;
  1262.         return OK;
  1263.     }
  1264.  
  1265. /*
  1266.  * get a name for the temp file
  1267.  */
  1268.     STRCPY(tmpname, TMPNAME2);
  1269.     if (*mktemp((char *)tmpname) == NUL)
  1270.     {
  1271.         emsg(e_notmp);
  1272.         return FAIL;
  1273.     }
  1274.  
  1275. /*
  1276.  * let the shell expand the patterns and write the result into the temp file
  1277.  * If we use csh, glob will work better than echo.
  1278.  */
  1279.     if ((len = STRLEN(p_sh)) >= 3 && STRCMP(p_sh + len - 3, "csh") == 0)
  1280.         use_glob = TRUE;
  1281.  
  1282.     len = TMPNAMELEN + 11;
  1283.     for (i = 0; i < num_pat; ++i)        /* count the length of the patterns */
  1284.         len += STRLEN(pat[i]) + 3;
  1285.     command = alloc(len);
  1286.     if (command == NULL)
  1287.         return FAIL;
  1288.     if (use_glob)
  1289.         STRCPY(command, "glob >");        /* built the shell command */
  1290.     else
  1291.         STRCPY(command, "echo >");        /* built the shell command */
  1292.     STRCAT(command, tmpname);
  1293.     for (i = 0; i < num_pat; ++i)
  1294.     {
  1295. #ifdef USE_SYSTEM
  1296.         STRCAT(command, " \"");                /* need extra quotes because we */
  1297.         STRCAT(command, pat[i]);            /*   start the shell twice */
  1298.         STRCAT(command, "\"");
  1299. #else
  1300.         STRCAT(command, " ");
  1301.         STRCAT(command, pat[i]);
  1302. #endif
  1303.     }
  1304. #ifdef WEBB_COMPLETE
  1305.     if (expand_interactively)
  1306.         show_shell_mess = FALSE;
  1307. #endif /* WEBB_COMPLETE */
  1308.     if (use_glob)                            /* Use csh fast option */
  1309.         extra_shell_arg = (char_u *)"-f";
  1310.     i = call_shell(command, 0, FALSE);        /* execute it */
  1311.     extra_shell_arg = NULL;
  1312.     show_shell_mess = TRUE;
  1313.     free(command);
  1314.     if (i == FAIL)                            /* call_shell failed */
  1315.     {
  1316.         remove((char *)tmpname);
  1317. #ifdef WEBB_COMPLETE
  1318.         /* With interactive completion, the error message is not printed */
  1319.         if (!expand_interactively)
  1320. #endif /* WEBB_COMPLETE */
  1321.         {
  1322.             must_redraw = CLEAR;            /* probably messed up screen */
  1323.             msg_outchar('\n');                /* clear bottom line quickly */
  1324.             cmdline_row = Rows - 1;            /* continue on last line */
  1325.         }
  1326.         return FAIL;
  1327.     }
  1328.  
  1329. /*
  1330.  * read the names from the file into memory
  1331.  */
  1332.      fd = fopen((char *)tmpname, "r");
  1333.     if (fd == NULL)
  1334.     {
  1335.         emsg2(e_notopen, tmpname);
  1336.         return FAIL;
  1337.     }
  1338.     fseek(fd, 0L, SEEK_END);
  1339.     len = ftell(fd);                /* get size of temp file */
  1340.     fseek(fd, 0L, SEEK_SET);
  1341.     buffer = alloc(len + 1);
  1342.     if (buffer == NULL)
  1343.     {
  1344.         remove((char *)tmpname);
  1345.         fclose(fd);
  1346.         return FAIL;
  1347.     }
  1348.     i = fread((char *)buffer, 1, len, fd);
  1349.     fclose(fd);
  1350.     remove((char *)tmpname);
  1351.     if (i != len)
  1352.     {
  1353.         emsg2(e_notread, tmpname);
  1354.         free(buffer);
  1355.         return FAIL;
  1356.     }
  1357.  
  1358.     if (use_glob)        /* file names are separated with NUL */
  1359.     {
  1360.         buffer[len] = NUL;                    /* make sure the buffers ends in NUL */
  1361.         i = 0;
  1362.         for (p = buffer; p < buffer + len; ++p)
  1363.             if (*p == NUL)                    /* count entry */
  1364.                 ++i;
  1365.         if (len)
  1366.             ++i;                            /* count last entry */
  1367.     }
  1368.     else                /* file names are separated with SPACE */
  1369.     {
  1370.         buffer[len] = '\n';                    /* make sure the buffers ends in NL */
  1371.         p = buffer;
  1372.         for (i = 0; *p != '\n'; ++i)        /* count number of entries */
  1373.         {
  1374.             while (*p != ' ' && *p != '\n')    /* skip entry */
  1375.                 ++p;
  1376.             skipspace(&p);                    /* skip to next entry */
  1377.         }
  1378.     }
  1379.     *num_file = i;
  1380.     *file = (char_u **)alloc(sizeof(char_u *) * i);
  1381.     if (*file == NULL)
  1382.     {
  1383.         free(buffer);
  1384.         *file = (char_u **)"";
  1385.         return FAIL;
  1386.     }
  1387.     p = buffer;
  1388.     for (i = 0; i < *num_file; ++i)
  1389.     {
  1390.         (*file)[i] = p;
  1391.         if (use_glob)
  1392.         {
  1393.             while (*p && p < buffer + len)        /* skip entry */
  1394.                 ++p;
  1395.             ++p;                                /* skip NUL */
  1396.         }
  1397.         else
  1398.         {
  1399.             while (*p != ' ' && *p != '\n')        /* skip entry */
  1400.                 ++p;
  1401.             if (*p == '\n')                        /* last entry */
  1402.                 *p = NUL;
  1403.             else
  1404.             {
  1405.                 *p++ = NUL;
  1406.                 skipspace(&p);                    /* skip to next entry */
  1407.             }
  1408.         }
  1409.     }
  1410.     for (i = 0; i < *num_file; ++i)
  1411.     {
  1412.         dir = (isdir((*file)[i]) == TRUE);
  1413.         if (dir < 0)            /* if file doesn't exist don't add '/' */
  1414.             dir = 0;
  1415.         p = alloc((unsigned)(STRLEN((*file)[i]) + 1 + dir));
  1416.         if (p)
  1417.         {
  1418.             STRCPY(p, (*file)[i]);
  1419.             if (dir)
  1420.                 STRCAT(p, "/");
  1421.         }
  1422.         (*file)[i] = p;
  1423.     }
  1424.     free(buffer);
  1425.     return OK;
  1426. }
  1427.  
  1428.     void
  1429. FreeWild(num, file)
  1430.     int        num;
  1431.     char_u    **file;
  1432. {
  1433.     if (file == NULL || num == 0)
  1434.         return;
  1435.     while (num--)
  1436.         free(file[num]);
  1437.     free(file);
  1438. }
  1439.  
  1440.     int
  1441. has_wildcard(p)
  1442.     char_u *p;
  1443. {
  1444. #ifdef __STDC__
  1445.     return strpbrk((char *)p, "*?[{`~$") != NULL;
  1446. #else
  1447.     for ( ; *p; ++p)
  1448.         if (STRCHR("*?[{`~$", *p) != NULL)
  1449.             return 1;
  1450.     return 0;
  1451. #endif
  1452. }
  1453.  
  1454.     int
  1455. have_wildcard(num, file)
  1456.     int        num;
  1457.     char_u    **file;
  1458. {
  1459.     register int i;
  1460.  
  1461.     for (i = 0; i < num; i++)
  1462.         if (has_wildcard(file[i]))
  1463.             return 1;
  1464.     return 0;
  1465. }
  1466.  
  1467. #if defined(M_XENIX) || defined(UTS2)
  1468. /*
  1469.  * Scaled-down version of rename, which is missing in Xenix.
  1470.  * This version can only move regular files and will fail if the
  1471.  * destination exists.
  1472.  */
  1473.     int
  1474. rename(src, dest)
  1475.     char_u *src, *dest;
  1476. {
  1477.     struct stat        st;
  1478.  
  1479.     if (stat(dest, &st) >= 0)    /* fail if destination exists */
  1480.         return -1;
  1481.     if (link(src, dest) != 0)    /* link file to new name */
  1482.         return -1;
  1483.     if (unlink(src) == 0)        /* delete link to old name */
  1484.         return 0;
  1485.     return -1;
  1486. }
  1487. #endif /* M_XENIX || UTS2 */
  1488.